package com.loveprogrammer.eternity.model;

import com.loveprogrammer.eternity.common.Tuple;
import com.loveprogrammer.eternity.enums.AttackTypeEnum;
import com.loveprogrammer.eternity.enums.ConsoleColors;
import com.loveprogrammer.eternity.enums.MonsterQualityEnum;
import com.loveprogrammer.eternity.enums.QualityEnum;
import com.loveprogrammer.eternity.factory.template.MapTemplate;
import com.loveprogrammer.eternity.factory.template.MonsterTemplate;
import com.loveprogrammer.eternity.model.attack.AttackEntity;
import com.loveprogrammer.eternity.model.attack.AttackResult;
import com.loveprogrammer.eternity.model.product.Coin;
import com.loveprogrammer.eternity.model.product.equipment.Equips;
import com.loveprogrammer.eternity.skill.Skill;
import com.loveprogrammer.eternity.skill.State;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @version 1.0.0
 * @description:
 * @author: eric
 * @date: 2022-08-02 18:18
 **/
public class Monster extends Character {

    private MonsterTemplate template;

    // 品质
    private QualityEnum qualityEnum;

    // TODO
    private List<MapTemplate.Drop> dropList;

    // 读档的时候用
    public Monster(String name, int strength, int armature, int constitution, int magic, int technique, int speed,
                   AtomicInteger hp, int hpMax, int baseStrength, int baseArmature, int baseConstitution, int baseMagic,
                   int baseTechnique, int baseSpeed, int baseHp, int level, MonsterQualityEnum monsterQualityEnum,
                   Integer currentExp, Integer nextLevelNeedExp, Equips equips,
                   List<Skill> skills, List<State> states, int attackType, MonsterTemplate template,
                   QualityEnum qualityEnum, int poisonResistance,
                   int flameResistance, int thunderResistance,int iceResistance,int position) {
        super(template.getId(),name,strength,armature,constitution,magic,technique,speed,hp,hpMax,baseStrength,baseArmature,
                baseConstitution,baseMagic,baseTechnique,baseSpeed,baseHp,level,monsterQualityEnum,currentExp,
                nextLevelNeedExp,equips,skills,states,attackType,poisonResistance,flameResistance,thunderResistance,iceResistance,position);
        this.template = template;
        this.qualityEnum = qualityEnum;
    }

    public Monster(String name, int level, int strength, int armature, int constitution,
                   int magic, int technique ,int speed, int attackType,
                   MonsterQualityEnum monsterQualityEnum,QualityEnum qualityEnum,
                   MonsterTemplate monsterTemplate, int poisonResistance,
                   int flameResistance, int thunderResistance, int iceResistance,int position) {
        super(monsterTemplate.getId(),name, level, strength, armature, constitution,magic,technique,speed,attackType,poisonResistance,
                flameResistance,thunderResistance,iceResistance,position);
        this.monsterQualityEnum = monsterQualityEnum;
        if(monsterTemplate == null){
            monsterTemplate = new MonsterTemplate();
        }
        this.template = monsterTemplate;
        this.qualityEnum = qualityEnum;
    }

    public Monster(MonsterTemplate template,QualityEnum qualityEnum){
        super(template.getId(),template.getName(), 1, template.getStrength(), template.getArmature(),
                template.getConstitution(),template.getMagic(),template.getTechnique(),template.getSpeed(),
                template.getAttackType()
                ,template.getPoisonResistance(),
                template.getFlameResistance(),
                template.getThunderResistance(),
                template.getIceResistance(),template.getPosition());
        this.monsterQualityEnum = MonsterQualityEnum.getByLevel(template.getQuality());
        this.template = template;
        this.qualityEnum = qualityEnum;
    }

    @Override
    public int getDeadExp() {
        return (int) (level * monsterQualityEnum.getCode() * monsterQualityEnum.getCode() * getTemplate().getExp());
    }

    @Override
    protected AttackEntity getHarm() {
        // 根据不同的英雄 力 法
        if(getAttackType() == 1) {
            return new AttackEntity(this.magic, AttackTypeEnum.MAGIC);
        }
        return new AttackEntity(this.strength, AttackTypeEnum.NORMAL);
    }

    @Override
    public void levelUp(int exp) {
        this.setLevel(this.level + 1);
        // 检查技能升级情况
        if(!this.getSkills().isEmpty()){
            this.getSkills().forEach(e -> e.levelUp(this.getLevel()));
        }
        // 属性增加
        this.setStrength((int) (this.strength + template.getLevelUpStrength() * qualityEnum.getRatio()));
        this.setTechnique((int) (this.technique + template.getLevelUpTechnique()* qualityEnum.getRatio()));
        this.setArmature((int) (this.armature + template.getLevelUpArmature()* qualityEnum.getRatio()));
        this.setConstitution((int) (this.constitution + template.getLevelUpConstitution()* qualityEnum.getRatio()));
        this.hp.addAndGet((int) (10 * template.getLevelUpConstitution() * qualityEnum.getRatio()));
        this.hpMax = this.hp.get();
        this.setMagic((int) (this.magic + template.getLevelUpMagic()* qualityEnum.getRatio()));
        this.setSpeed((int) (this.speed + template.getLevelUpSpeed()* qualityEnum.getRatio()));
        // 基础属性增加
        this.setBaseStrength((int) (this.getBaseStrength() + template.getLevelUpStrength()* qualityEnum.getRatio()));
        this.setBaseMagic((int) (this.getBaseMagic() + template.getLevelUpMagic()* qualityEnum.getRatio()));
        this.setBaseTechnique((int) (this.getBaseTechnique() + template.getLevelUpTechnique()* qualityEnum.getRatio()));
        this.setBaseArmature((int) (this.getBaseArmature() + template.getLevelUpArmature()* qualityEnum.getRatio()));
        this.setBaseConstitution((int) (this.getBaseConstitution() + template.getLevelUpConstitution()* qualityEnum.getRatio()));
        this.setBaseSpeed((int) (this.getBaseSpeed() + template.getLevelUpSpeed()* qualityEnum.getRatio()));
        // 计算下一级需要的经验值
        int needExp = this.setNextLevelNeedExp();
        if(exp > needExp){
            levelUp(exp);
        }
    }

    @Override
    public void reset() {

    }

    public Monster upLevel(int level){
        this.strength = (int) (level * template.getLevelUpStrength() * qualityEnum.getRatio() + template.getStrength());
        this.armature = (int) (level * template.getLevelUpArmature() * qualityEnum.getRatio() + template.getArmature());
        this.constitution = (int) (level * template.getLevelUpConstitution() * qualityEnum.getRatio() + template.getConstitution());
        this.magic = (int) (level * template.getLevelUpMagic() * qualityEnum.getRatio() + template.getMagic());
        this.technique = (int) (level * template.getLevelUpTechnique() * qualityEnum.getRatio() + template.getTechnique());
        this.speed = (int) (level * template.getLevelUpSpeed() * qualityEnum.getRatio() + template.getSpeed());
        this.hp.set(Optional.of(this.constitution * 10).orElse(0));
        this.hpMax = this.hp.get();
        return this;
    }

    @Override
    public Tuple<String, List<Character>> attack(List characters) {
        Tuple<String,List<Character>> result = new Tuple<>();
        List<Character> list = characters;
        ArrayList<Character> defences = new ArrayList<>();
        // 暂定一次只能攻击一个
        Character defence = findSingleAttacker(list, true);

        StringBuilder builder = new StringBuilder();
        builder.append(this.name).append("(").append(getCurrentHp()).append("/")
                .append(getHpMax()).append(")").append("攻击了").append(defence.getName());

        // 普通攻击， 按照血量排序，攻击血量最低的
        AttackEntity harm = getHarm();
        // 暴击检测
        boolean crit = critCheck(this);
        if(crit) {
            harm.setHarm(critPower(harm.getHarm()));
        }
        AttackResult attackResult = defence.defence(harm);
        computeHarm(builder,crit,defence,attackResult,this,null,defences);
        defences.add(defence);

        result.setKey(builder.toString());
        result.setValue(defences);
        return result;
    }

    public MonsterTemplate getTemplate() {
        return template;
    }

    //角色打印信息的重写
    public String toString() {
        return "**** 名称：" + this.name + " " +
                "级别" + this.level + " " +
                "天赋" + this.qualityEnum.getColor() + this.qualityEnum.getDesc() + ConsoleColors.RESET + " " +
                "品质" + this.monsterQualityEnum.getDesc() + " " +
                "血量：" + this.hp + " " +
                "护甲值: " + this.armature + " " +
                "力量:" + this.strength + " " +
                "法力:" + this.magic + " " +
                "技巧:" + this.technique + " " +
                "速度:" + this.speed + " " +
                "抗性[毒:" + this.getPoisonResistance() + " 火:" + this.getFlameResistance()
                + " 雷:" + this.getThunderResistance() + " 冰:" + this.getIceResistance() + "] " +
                "经验(" + this.currentExp + "/" + this.nextLevelNeedExp + ") ****";
    }

    public QualityEnum getQualityEnum() {
        return qualityEnum;
    }

    public void setQualityEnum(QualityEnum qualityEnum) {
        this.qualityEnum = qualityEnum;
    }

    public void setTemplate(MonsterTemplate template) {
        this.template = template;
    }

    public List<MapTemplate.Drop> getDropList() {
        return dropList;
    }

    public void setDropList(List<MapTemplate.Drop> dropList) {
        this.dropList = dropList;
    }

    @Override
    public Coin sale() {
        Coin coin = new Coin();
        int silverCoin = (int) (score() + getLevel() * getQualityEnum().getRatio());
        coin.setGoldCoin(silverCoin);
        return coin;
    }

    public int score() {
        return strength + armature * 2 + constitution + magic + technique + speed / 2;
    }
}
